package com.hiwan.system.service.file;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.hiwan.platform.util.StackTraceUtil;
import com.hiwan.system.dao.file.FileInfoDao;
import com.hiwan.system.pojo.FileInfo;
import com.hiwan.system.pojo.HiwanFile;
import com.hiwan.system.util.UserCacheUtils;

@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Service
public class FileService {
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Value("${com.hiwan.file.temp.path}")
	private String tempPath;
	@Value("${com.hiwan.file.path}")
	private String filePath;
	
	@Autowired
	private FileInfoDao fileInfoDao;

	/***
	 * 根据文件名、地区号、文件类型获取对应的文件对象
	 * 
	 * @param fileName
	 *            文件名
	 * @param orgId
	 *            所属地区
	 * @param isTemp
	 *            文件类型: 0-临时文件；1-正式文件
	 * @return
	 */
	public HiwanFile getFile(String fileName, String orgId, String isTemp) {
		String fileFullName = null;
		if ("1".equals(isTemp)) {
			fileFullName = filePath + File.separator + orgId + File.separator
					+ fileName;
		} else {
			fileFullName = tempPath + File.separator + orgId + File.separator
					+ fileName;
		}
		File file = new File(fileFullName);
		return new HiwanFile(file);
	}

	/***
	 * 向临时目录写文件（如文件已存在则续写）
	 * 
	 * @param fileName
	 *            文件名
	 * @param orgId
	 *            所属地区
	 * @param fileType
	 *            文件类型
	 * @param bytes
	 *            文件内容
	 * @return
	 */
	public boolean writeTempFile(String fileName, String orgId, byte[] bytes) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + fileName;
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}

			BufferedOutputStream buff = new BufferedOutputStream(
					new FileOutputStream(file, true));
			buff.write(bytes);
			buff.flush();
			buff.close();

			return true;
		} catch (IOException e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}

	public boolean writeTempFile(String orgId, HiwanFile hiwanfile, int chunk) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + hiwanfile.getFileName();
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			if (chunk == 0 && file.exists()) {
				file.delete();
			}
			BufferedOutputStream buff = null;
			if (!file.exists()) {
				buff = new BufferedOutputStream(
						new FileOutputStream(file, true));
			} else {
				buff = new BufferedOutputStream(new FileOutputStream(file));
			}
			InputStream is = hiwanfile.getFileInputStream();
			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				buff.write(b, 0, length);
			}
			buff.write(b);
			buff.flush();
			buff.close();

			return true;
		} catch (IOException e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}

	}
	
	public boolean writeTempFile(String orgId, MultipartFile multipartFile, String newName) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + newName;
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			InputStream is = multipartFile.getInputStream();
			FileOutputStream os = new FileOutputStream(file);

			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				os.write(b, 0, length);
			}
			os.flush();
			os.close();
			return true;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}

	public boolean writeTempFile(String orgId, MultipartFile multipartFile, String newName,
			int chunk) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + newName;
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			if (chunk == 0 && file.exists()) {
				file.delete();
			}
			BufferedOutputStream buff = null;
			if (!file.exists()) {
				buff = new BufferedOutputStream(
						new FileOutputStream(file, true));
			} else {
				buff = new BufferedOutputStream(new FileOutputStream(file));
			}
			InputStream is = multipartFile.getInputStream();
			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				buff.write(b, 0, length);
			}
			buff.write(b);
			buff.flush();
			buff.close();

			return true;
		} catch (IOException e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}

	}

	/***
	 * 把文件从临时空间写到文件服务器
	 * 
	 * @param fileName
	 *            文件名
	 * @param orgId
	 *            所属地区
	 * @param fileType
	 *            文件类型
	 * @param bytes
	 *            文件内容
	 * @return
	 */
	public boolean saveTempFile(String orgId, String fileName) {
		String fileFullName = filePath + File.separator + orgId
				+ File.separator + fileName;
		HiwanFile tempFile = getFile(fileName, orgId, "0");
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			InputStream is = tempFile.getFileInputStream();
			FileOutputStream os = new FileOutputStream(file);

			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				os.write(b, 0, length);
			}
			os.flush();
			os.close();
			return true;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}

	/**
	 * 把文件从临时空间写到正式目录
	 * 
	 * @param orgId
	 *            文件归属机构
	 * @param fileName
	 *            临时文件名
	 * @param dstFileName
	 *            正式文件名
	 * @return
	 */
	public boolean saveTempFile(String orgId, String fileName,
			String dstFileName) {
		String fileFullName = filePath + File.separator + orgId
				+ File.separator + dstFileName;
		HiwanFile tempFile = this.getFile(fileName, orgId, "");
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			InputStream is = tempFile.getFileInputStream();
			FileOutputStream os = new FileOutputStream(file);

			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				os.write(b, 0, length);
			}
			os.flush();
			os.close();
			return true;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}

	/**
	 * 向临时目录拷贝文件
	 * 
	 * @param orgId
	 * @param applyFile
	 * @return
	 */
	public boolean writeTempFile(String orgId, HiwanFile applyFile) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + applyFile.getFileName();
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			InputStream is = applyFile.getFileInputStream();
			FileOutputStream os = new FileOutputStream(file);

			byte[] b = new byte[1024];
			int length;
			while ((length = is.read(b)) > 0) {
				os.write(b, 0, length);
			}
			os.flush();
			os.close();
			return true;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}

	/**
	 * 删除上传文件
	 * 
	 * @param orgId
	 * @param fileName
	 * @param deleteType
	 *            0-临时文件；1-正式文件
	 * @return
	 */
	public boolean deleteFile(FileInfo fileInfo,String deleteType) {
		String fileFullName = tempPath + File.separator + fileInfo.getBelongOrg()
				+ File.separator + fileInfo.getFileName();
		if ("1".equals(deleteType)) {
			fileFullName = filePath + File.separator + fileInfo.getBelongOrg() + File.separator
					+ fileInfo.getFileName();
		}
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) { 
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return false;
			}
			file.delete();
			fileInfoDao.delete(fileInfo);
			return true;
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return false;
		}
	}
	
	
	/***
	 * 创建文件并获取文件输出流(如文件已存在则覆盖重新创建)
	 * 
	 * @param fileName
	 *            文件名
	 * @param orgId
	 *            所属地区
	 * @param fileType
	 *            文件类型
	 * @return 文件输出流（可进行写操作）,返回null则表示创建文件失败
	 */
	public FileOutputStream createFile(String fileName, String orgId) {
		String fileFullName = tempPath + File.separator + orgId
				+ File.separator + fileName;
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return null;
			}

			return new FileOutputStream(file);
		} catch (IOException e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return null;
		}
	}
	
	
	/**
	 * 上传文件并保存
	 * @param fileName
	 * @param orgId
	 * @return
	 */
	public String createFile(String busiId, String orgId, MultipartFile applyFile) {
		String originName = applyFile.getOriginalFilename();
		int idx = originName.lastIndexOf('.');
		String fileName =  UUID.randomUUID().toString();
		String fileFullName;
		String fileResult;
		
		if (StringUtils.isBlank(busiId)){
			fileResult = File.separator + (StringUtils.isBlank(orgId)?UserCacheUtils.getOrgId():orgId) + File.separator + fileName + originName.substring(idx);
		}else{
			fileResult = File.separator + busiId + File.separator + (StringUtils.isBlank(orgId)?UserCacheUtils.getOrgId():orgId) + File.separator + fileName + originName.substring(idx);			 
		}
		fileFullName = filePath + fileResult;
		try {
			File file = new File(fileFullName);
			if (!file.getParentFile().exists()
					&& !file.getParentFile().mkdirs()) {
				logger.error("Can not create the directory for file : {}",
						fileFullName);
				return null;
			}
			applyFile.transferTo(file);
			return fileResult.replace("\\", "/");
		} catch (Exception e) {
			logger.error(StackTraceUtil.getStackTrace(e));
			return null;
		}
	}
	/**
	 * 封装多文件上传文件名称，文件名之间用","隔开
	 * 
	 * @param currentFileName
	 *            新增文件名
	 * @param operType
	 *            操作类型1--新增 2-删除
	 * @param oldFileName
	 *            已上传文件名
	 * @return
	 */
	public String setDisplayFileName(String currentFileName, String operType,
			String oldFileName) {
		if ("1".equals(operType)) {
			// 上传文件
			if (oldFileName == null || "".equals(oldFileName)) {
				oldFileName = currentFileName;
			} else {
				oldFileName += "|" + currentFileName;
			}
		} else if ("2".equals(operType)) {
			// 删除文件
			StringBuffer sb = new StringBuffer();
			if (oldFileName != null && !"".equals(oldFileName)) {
				String[] fileStr = oldFileName.split("\\|");
				if (fileStr != null && fileStr.length > 0) {
					for (int i = 0; i < fileStr.length; i++) {
						if (fileStr[i].equals(currentFileName)) {
							continue;
						} else {
							if (sb.toString() == null
									|| "".equals(sb.toString())) {
								sb.append(fileStr[i]);
							} else {
								sb.append("|" + fileStr[i]);
							}
						}
					}
				}
			}
			oldFileName = sb.toString();
		}
		return oldFileName;
	}

	public boolean deleteFile(HiwanFile file) {
		return file.delete();
	}
}
